package com.fulihui.usercore.biz.jobs;

import com.fulihui.systemcore.dto.WechatConfig;
import com.fulihui.systemcore.enums.WechatTokenTypeEnum;
import com.fulihui.systemcore.request.wechat.WechatTokenRequest;
import com.fulihui.usercore.biz.shard.WechatConfigFactory;
import com.fulihui.usercore.common.integration.WechatTokenServiceClient;
import com.fulihui.usercore.common.util.LoggerNames;
import com.fulihui.usercore.dal.dataobj.UnionidOpenidDO;
import com.fulihui.usercore.dal.mapper.UnionidOpenidMapper;
import com.fulihui.weixinclient.WeixinClient;
import com.fulihui.weixinclient.model.UserBatchGetCondition;
import com.fulihui.weixinclient.model.WechatUser;
import com.fulihui.weixinclient.request.UserInfoBatchGetWeixinRequest;
import com.fulihui.weixinclient.request.UserListWeixinRequest;
import com.fulihui.weixinclient.result.UserInfoBatchGetWeixinResult;
import com.fulihui.weixinclient.result.UserListWeixinResult;
import org.near.servicesupport.request.RequestBuilder;
import org.near.toolkit.common.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 同步所有已关注微信用户的openid和unionid，1小时执行一次
 * Created by Willard.Hu on 2016/8/18.
 */
@Component
public class SyncSubscribedWechatUserOpenidUnionidJob {
    private final transient Logger JOB_MONITOR = LoggerFactory
            .getLogger(LoggerNames.JOBS_MONITOR);
    private final transient Logger LOG = LoggerFactory.getLogger(getClass());
    @Autowired
    private WeixinClient weixinClient;
    @Autowired
    private WechatTokenServiceClient wechatTokenServiceClient;
    @Autowired
    private WechatConfigFactory wechatConfigFactory;
    @Autowired
    private UnionidOpenidMapper unionidOpenidMapper;


    public void process() {
        JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob, start, time:{}", new Date());
        WechatConfig wechatConfig = wechatConfigFactory.get();
        WechatTokenRequest wechatTokenRequest = RequestBuilder.build(WechatTokenRequest.class);
        wechatTokenRequest.setAppid(wechatConfig.getAppID());
        wechatTokenRequest.setSecret(wechatConfig.getAppsecret());
        wechatTokenRequest.setTokenType(WechatTokenTypeEnum.ACCESS_TOKEN.getCode());
        String token = wechatTokenServiceClient.getToken(wechatTokenRequest);
        UserListWeixinRequest userListWeixinRequest = new UserListWeixinRequest();
        userListWeixinRequest.setAccess_token(token);
        int executeCount = 0;
        while (true) {
            UserListWeixinResult userListWeixinResult = weixinClient
                    .invokeService(userListWeixinRequest);
            JOB_MONITOR
                    .info(
                            "SyncSubscribedWechatUserOpenidUnionidJob, batchExecute, total:{}, executeCount:{}",
                            userListWeixinResult.getTotal(), executeCount);
            batchExecute(userListWeixinResult.getData().getOpenid());
            executeCount += userListWeixinResult.getCount();
            if (executeCount == userListWeixinResult.getTotal()) {
                break;
            }
            userListWeixinRequest.setNext_openid(userListWeixinResult.getNext_openid());
        }
        JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob, end, time:{}", new Date());
    }

    private void batchExecute(List<String> openIds) {
        if (CollectionUtils.isEmpty(openIds)) {
            return;
        }
        List<String> needInsert = new ArrayList<>();
        List<String> needUpdate = new ArrayList<>();
        for (String openid : openIds) {
            UnionidOpenidDO item = unionidOpenidMapper.queryByOpenid(openid);
            if (item == null) {
                needInsert.add(openid);
            } else if (StringUtil.isBlank(item.getUnionid())) {
                needUpdate.add(openid);
            }
            if (needUpdate.size() == 100) {
                try {
                    JOB_MONITOR
                            .info("SyncSubscribedWechatUserOpenidUnionidJob update data size:100");
                    unionidOpenidMapper.update(conv(queryRemote(needUpdate)));
                    JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob update end, clear");
                    needUpdate.clear();
                } catch (Exception e) {
                    JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob update error, {}",
                            e.getMessage());
                    LOG.info(e.getMessage(), e);
                }
            }
            if (needInsert.size() == 100) {
                try {
                    JOB_MONITOR
                            .info("SyncSubscribedWechatUserOpenidUnionidJob insert data size:100");
                    unionidOpenidMapper.insert(conv(queryRemote(needInsert)));
                    JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob insert end, clear");
                    needInsert.clear();
                } catch (Exception e) {
                    JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob insert error, {}",
                            e.getMessage());
                    LOG.info(e.getMessage(), e);
                }
            }
        }
        if (!CollectionUtils.isEmpty(needUpdate)) {
            try {
                JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob update data size:{}",
                        needUpdate.size());
                unionidOpenidMapper.update(conv(queryRemote(needUpdate)));
                JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob update end, clear");
                needUpdate.clear();
            } catch (Exception e) {
                JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob update error, {}",
                        e.getMessage());
                LOG.info(e.getMessage(), e);
            }
        }
        if (!CollectionUtils.isEmpty(needInsert)) {
            try {
                JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob insert data size:{}",
                        needInsert.size());
                unionidOpenidMapper.insert(conv(queryRemote(needInsert)));
                JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob insert end, clear");
                needInsert.clear();
            } catch (Exception e) {
                JOB_MONITOR.info("SyncSubscribedWechatUserOpenidUnionidJob insert error, {}",
                        e.getMessage());
                LOG.info(e.getMessage(), e);
            }
        }
    }

    private List<WechatUser> queryRemote(List<String> openid) {
        List<UserBatchGetCondition> conditions = openid.stream().map(it -> {
            UserBatchGetCondition condition = new UserBatchGetCondition();
            condition.setOpenid(it);
            return condition;
        }).collect(Collectors.toList());

        WechatConfig wechatConfig = wechatConfigFactory.get();
        WechatTokenRequest wechatTokenRequest = RequestBuilder.build(WechatTokenRequest.class);
        wechatTokenRequest.setAppid(wechatConfig.getAppID());
        wechatTokenRequest.setSecret(wechatConfig.getAppsecret());
        wechatTokenRequest.setTokenType(WechatTokenTypeEnum.ACCESS_TOKEN.getCode());
        String token = wechatTokenServiceClient.getToken(wechatTokenRequest);

        UserInfoBatchGetWeixinRequest userInfoBatchGetWeixinRequest = new UserInfoBatchGetWeixinRequest();
        userInfoBatchGetWeixinRequest.setAccess_token(token);
        userInfoBatchGetWeixinRequest.setUser_list(conditions);
        UserInfoBatchGetWeixinResult result = weixinClient
                .invokeService(userInfoBatchGetWeixinRequest);
        return result.getUser_info_list();
    }

    private List<UnionidOpenidDO> conv(List<WechatUser> users) {
        return users.stream().map(it -> {
            UnionidOpenidDO item = new UnionidOpenidDO();
            item.setOpenId(it.getOpenid());
            item.setUnionid(it.getUnionid());
            return item;
        }).collect(Collectors.toList());
    }
}
